import { StockDailyData, StockInfo } from "./types";
import path from "path";
import fs from "fs";
import { delay } from '../util/time'
import { proxies } from '../config'
import axios from 'axios';
import { Agent } from 'https';
const agent = new Agent({
    ciphers: [
      'TLS_AES_128_GCM_SHA256',
      'TLS_AES_256_GCM_SHA384',
      'TLS_CHACHA20_POLY1305_SHA256',
      'ECDHE-RSA-AES128-GCM-SHA256',
      'ECDHE-RSA-AES256-GCM-SHA384',
    ].join(':'),
    honorCipherOrder: false,
  });



const CommonHeaders = {
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Safari/537.36",
    "Accept": "application/json, text/plain, */*",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Accept-Encoding": "gzip, deflate, br",
}

//百度股市通 https://gushitong.baidu.com/stock/ab-600980

export async function getStockInfo(stockCode: string): Promise<StockInfo> {
    const url = `https://finance.pae.baidu.com/vapi/v1/getquotation?srcid=5353&all=1&code=${stockCode}&query=${stockCode}&eprop=min&group=quotation_minute_ab&stock_type=ab&chartType=minute&finClientType=pc&t=${new Date().getTime()}`;
    const controller = new AbortController();
    const timeout = setTimeout(() => controller.abort(), 60000);
    try {
        const res = await fetch(url, {
            method: 'GET',
            headers: { ...CommonHeaders, "Referer": `https://gushitong.baidu.com/stock/ab-${stockCode}` },
            signal: controller.signal,
        } as any);
        clearTimeout(timeout);
        if (!res.ok) {
            throw new Error(`HTTP ${res.status}`);
        }
        const data = await res.json();
        if (data.ResultCode !== 0) {
            throw new Error(`get stock info failed: ${data.ResultMsg}`);
        }
        const stockInfo = {} as any;
        stockInfo.name = data.Result.basicinfos.name;
        stockInfo.code = data.Result.basicinfos.code;
        data.Result.pankouinfos.list.forEach((it: { ename: string, originValue: string }) => {
            if (it.originValue) {
                stockInfo[it.ename] = Number(it.originValue);
            }
        });
        return stockInfo as StockInfo;
    } finally {
        clearTimeout(timeout);
    }
}



function createGetStockDayDataFromBaidu(proxyHost?: string, proxyPort?: number, proxyUser?: string, proxyPassword?: string) {
    return async function (
        stockCode: string,
        startDate: string,
        endDate: string,
        period: "D" | "W" | "M" | "MIN1" | "MIN5" | "MIN15" | "MIN30" | "MIN60"): Promise<StockDailyData[]> {
        const ktype = {
            "D": "day",
            "W": "week",
            "M": "month",
            "MIN1": "min1",
            "MIN5": "min5",
            "MIN15": "min15",
            "MIN30": "min30",
            "MIN60": "min60",
        }[period];
        const url = `https://finance.pae.baidu.com/vapi/v1/getquotation?srcid=5353&pointType=string&group=quotation_kline_ab&query=${stockCode}&code=${stockCode}&market_type=ab&newFormat=1&is_kc=0&ktype=${ktype}&finClientType=pc`;
        // console.info(`history data from baidu: ${url}`)
        const response = await axios.get(url,
            {
                httpsAgent: agent,
                headers: {
                    ...CommonHeaders,
                    "Referer": `https://gushitong.baidu.com/stock/ab-${stockCode}`,
                    "Host": "finance.pae.baidu.com"
                },
                timeout: 60000,
                proxy: {
                    host: proxyHost,
                    port: proxyPort,
                    protocol: "http",
                    auth: {
                        username: proxyUser,
                        password: proxyPassword
                    }
                }
            }
        );

        if(response.status !== 200){
            throw new Error(`get stock history data failed: ${response.status}`);
        }
        if(!startDate.includes(' ')){
            startDate += ' 00:00:00';
        }
        if(!endDate.includes(' ')){
            endDate += ' 23:59:59';
        }
        const data = response.data;
        const stockDayData = data.Result;
        const headers = stockDayData.newMarketData.headers as string[];
        const reusltList = [] as StockDailyData[];
        const values = stockDayData.newMarketData.marketData.split(";") as string[];
        for (let index = 0; index < values.length; index++) {
            const row = values[index].split(",");
            if (row[headers.indexOf("时间")] >= startDate && row[headers.indexOf("时间")] <= endDate) {
                reusltList.push({ date: row[headers.indexOf("时间")], open: Number(row[headers.indexOf("开盘")]), close: Number(row[headers.indexOf("收盘")]), high: Number(row[headers.indexOf("最高")]), low: Number(row[headers.indexOf("最低")]), volume: Number(row[headers.indexOf("成交量")]) / 100, amount: Number(row[headers.indexOf("成交额")]) });
            }
        }
        return reusltList;
    }
}


interface StockDataSource {
    name: string;
    func: (stockCode: string, startDate: string, endDate: string, period: "D" | "W" | "M" | "MIN1" | "MIN5" | "MIN15" | "MIN30" | "MIN60") => Promise<StockDailyData[]>;
    maxPerSecond?: number; // 每秒最大执行次数（可选，默认1）
}

class StockDataFetcher {
    private sources: StockDataSource[];
    private invokeHistory: Map<string, number[]> = new Map(); // 每个数据源1秒窗口内的调用时间戳
    private currentIndex = 0;

    constructor(sources: StockDataSource[]) {
        this.sources = sources;
        sources.forEach(s => this.invokeHistory.set(s.name, []));
    }

    public async getStockHistoryData(
        stockCode: string,
        startDate: string,
        endDate: string,
        period: "D" | "W" | "M" | "MIN1" | "MIN5" | "MIN15" | "MIN30" | "MIN60" = "D"
    ): Promise<StockDailyData[]> {
        const errors: string[] = [];
        for (let i = 0; i < this.sources.length; i++) {
            // Round-robin selection
            const source = this.sources[this.currentIndex];
            this.currentIndex = (this.currentIndex + 1) % this.sources.length;
            // console.log(`Using data source: ${source.name}`);

            try {
                // Rate limiting - per source, sliding window within 1000ms
                const maxPerSecond = source.maxPerSecond ?? 1;
                const history = this.invokeHistory.get(source.name)!;
                let now = Date.now();
                // 清理超过1秒的历史记录
                while (history.length && history[0] <= now - 1000) history.shift();
                if (history.length >= maxPerSecond) {
                    const waitMs = (history[0] + 1000) - now;
                    if (waitMs > 0) {
                        await delay(waitMs);
                        // 再次清理并更新时间
                        now = Date.now();
                        while (history.length && history[0] <= now - 1000) history.shift();
                    }
                }
                // 记录本次调用时间
                history.push(Date.now());

                // Attempt to fetch data
                const result = await source.func(stockCode, startDate, endDate, period);
                return result; // Success, return result
            } catch (error) {
                const errorMessage = `Failed to fetch from ${source.name}: ${error instanceof Error ? error.message : String(error)}`;
                console.error(errorMessage);
                errors.push(errorMessage);
            }
        }

        // If all sources failed
        throw new Error(`All data sources failed for ${stockCode}. Errors: [${errors.join(", ")}]`);
    }
}


const sources = []

if (proxies.length === 0) {
    // 无代理
    sources.push({
        name: `getStockDayDataFromBaidu-direct`,
        func: createGetStockDayDataFromBaidu(),
        maxPerSecond: 5,
    });
} else {
    for (const proxy of proxies) {
        sources.push({
            name: `getStockDayDataFromBaidu-${proxy.host}:${proxy.port}`,
            func: createGetStockDayDataFromBaidu(proxy.host, proxy.port, proxy.user, proxy.password)
        })
    }
}

const stockDataFetcher = new StockDataFetcher(sources);

export const getStockHistoryData = stockDataFetcher.getStockHistoryData.bind(stockDataFetcher);

/**
 * 获取所有A股股票代码和名称
 * @returns 
 */
export async function getStockCodeName(): Promise<{ code: string, name: string }[]> {
    //读取本地文件 data/a_stock_list.json
    const filePath = path.join(__dirname, 'a_stock_list.json');
    const fileContent = fs.readFileSync(filePath, 'utf-8');
    const stockList = JSON.parse(fileContent);
    return stockList;
}



// for (let i = 0; i < 6; i++) {
//     getStockHistoryData("600980", "2025-08-22", "2025-08-31", "MIN60").then((it: any) => {
//         console.log(it);
//     })
// }
